问:
Exported function being run in unit tests despite never calling it
I have the following class:

```<code>import { Observable } from 'rxjs/Observable';
import * as Logger from 'js-logger';

import { CookieParser } from './cookie-parser.service';
import { LogLevelConverter } from './loglevel-converter.service';
export class LoggerFactory {
  //Logging levels can be referenced like so: `LoggerFactory.WARN`
  public static readonly DEBUG = Logger.DEBUG;
  public static readonly INFO = Logger.INFO;
  public static readonly WARN = Logger.WARN;
  public static readonly ERROR = Logger.ERROR;
  public static readonly OFF = Logger.OFF;

  private static readonly LOG_LEVEL: string = 'FACTORY_LOG_LEVEL';
  private static initialized = false;

  public static getLogger(name: string): any {
    if (!LoggerFactory.initialized) {
      LoggerFactory.init(name);
    }

    return Logger.get(name);
  }

  private static init(name: string): void {
    //Set default logging level for LoggerFactory
    const DEFAULT_LOG_LEVEL = LoggerFactory.ERROR;
    Logger.setLevel(DEFAULT_LOG_LEVEL);

    let logLevel: string;

    if (window.document.cookie.indexOf(LoggerFactory.LOG_LEVEL) > -1) {
      logLevel = CookieParser.getCookieValue(LoggerFactory.LOG_LEVEL);
    } else if (LoggerFactory.isLocalStorageSupported()) {
      logLevel = localStorage.getItem(LoggerFactory.LOG_LEVEL);
    }

    if (logLevel) {
      Logger.get(name).setLevel(LogLevelConverter.toLogLevel(logLevel));
    } else {
      Logger.get(name).setLevel(DEFAULT_LOG_LEVEL);
    }

    LoggerFactory.initialized = true;
  }

  private static isLocalStorageSupported(): boolean {
    const testKey = 'test',
      storage = window.localStorage;
    try {
      storage.setItem(testKey, '1');
      storage.removeItem(testKey);
      return true;
    } catch (error) {
      return false;
    }
  }
}

/**
 * Used for logging the lifecycles of a component
 * Usage: @NgLifecycleLog()
 * @param  {string}         name for the logger
 * @return {ClassDecorator}
 */
export function NgLifecycleLog(name?: string): ClassDecorator {
  return function(constructor: any): void {
    const LIFECYCLE_HOOKS: Array<string> = ['ngOnInit', 'ngOnChanges', 'ngOnDestroy'];

    //If no name is given, default to using the component's constructor's name
    const NAME: string = name ? name : constructor.name;

    const lifecycleLogger = LoggerFactory.getLogger(NAME);

    console.error("SHOULDN'T BE CALLED"); //gets called

    LIFECYCLE_HOOKS.forEach(hook => {
      const original = constructor.prototype[hook];

      constructor.prototype[hook] = function(...args) {
        lifecycleLogger.info(`${hook}`, ...args);
        original.apply(this, args);
      };
    });
  };
}
</code>```

I also have the following unit test:

```<code>import { LoggerFactory } from './logger-factory.service';

describe('LoggerFactory', () => {
  localStorage.setItem('FACTORY_LOG_LEVEL', 'WARN');
  const LOGGER_NAME = 'unit.testing.name';
  const logger: any = LoggerFactory.getLogger(LOGGER_NAME);

  it('should provide a logger', () => {
    expect(logger).toBeDefined(logger);
  });

  it('should have the correct name', () => {
    expect(logger.context.name).toEqual(LOGGER_NAME);
  });

  it('should allow for localStorage log level overrides', () => {
    expect(logger.getLevel().name).toEqual('WARN');
  });
});
</code>```

My problem is that even though I'm never calling the NgLifecycleLog() method, it gets called. This is a problem because I'm trying to use LoggerFactory instead of console statements in it. When I run the unit test, a call to NgLifecycleLog() is made this causes an instance of LoggerFactory to be created when I am not expecting it to.

Why is this called? I've tried doing fdescribe on the tests to make sure this is the only thing being run and even then, that doesn't fix it.

答:
Class decorators are executed once, when decorated class is defined. If decorated class was included in test bundle, decorator function will be called.

If decorator function produces side effects or involves other units (this may affect unit tests), it should be refactored.

In this case a decorator patches class prototype methods:

```<code>const lifecycleLogger = LoggerFactory.getLogger(NAME);

LIFECYCLE_HOOKS.forEach(hook => {
  const original = constructor.prototype[hook];

  constructor.prototype[hook] = function(...args) {
    lifecycleLogger.info(`${hook}`, ...args);
    original.apply(this, args);
  };
});
</code>```

lifecycleLogger should be moved from the place where it is called on class decoration to the places where it is actually used:

```<code>LIFECYCLE_HOOKS.forEach(hook => {
  const original = constructor.prototype[hook];

  constructor.prototype[hook] = function(...args) {
    const lifecycleLogger = LoggerFactory.getLogger(NAME);
    lifecycleLogger.info(`${hook}`, ...args);
    original.apply(this, args);
  };
});
</code>```

Body:
I have the following class:

import { Observable } from 'rxjs/Observable';
import * as Logger from 'js-logger';

import { CookieParser } from './cookie-parser.service';
import { LogLevelConverter } from './loglevel-converter.service';
export class LoggerFactory {
  //Logging levels can be referenced like so: `LoggerFactory.WARN`
  public static readonly DEBUG = Logger.DEBUG;
  public static readonly INFO = Logger.INFO;
  public static readonly WARN = Logger.WARN;
  public static readonly ERROR = Logger.ERROR;
  public static readonly OFF = Logger.OFF;

  private static readonly LOG_LEVEL: string = 'FACTORY_LOG_LEVEL';
  private static initialized = false;

  public static getLogger(name: string): any {
    if (!LoggerFactory.initialized) {
      LoggerFactory.init(name);
    }

    return Logger.get(name);
  }

  private static init(name: string): void {
    //Set default logging level for LoggerFactory
    const DEFAULT_LOG_LEVEL = LoggerFactory.ERROR;
    Logger.setLevel(DEFAULT_LOG_LEVEL);

    let logLevel: string;

    if (window.document.cookie.indexOf(LoggerFactory.LOG_LEVEL) > -1) {
      logLevel = CookieParser.getCookieValue(LoggerFactory.LOG_LEVEL);
    } else if (LoggerFactory.isLocalStorageSupported()) {
      logLevel = localStorage.getItem(LoggerFactory.LOG_LEVEL);
    }

    if (logLevel) {
      Logger.get(name).setLevel(LogLevelConverter.toLogLevel(logLevel));
    } else {
      Logger.get(name).setLevel(DEFAULT_LOG_LEVEL);
    }

    LoggerFactory.initialized = true;
  }

  private static isLocalStorageSupported(): boolean {
    const testKey = 'test',
      storage = window.localStorage;
    try {
      storage.setItem(testKey, '1');
      storage.removeItem(testKey);
      return true;
    } catch (error) {
      return false;
    }
  }
}

/**
 * Used for logging the lifecycles of a component
 * Usage: @NgLifecycleLog()
 * @param  {string}         name for the logger
 * @return {ClassDecorator}
 */
export function NgLifecycleLog(name?: string): ClassDecorator {
  return function(constructor: any): void {
    const LIFECYCLE_HOOKS: Array<string> = ['ngOnInit', 'ngOnChanges', 'ngOnDestroy'];

    //If no name is given, default to using the component's constructor's name
    const NAME: string = name ? name : constructor.name;

    const lifecycleLogger = LoggerFactory.getLogger(NAME);

    console.error("SHOULDN'T BE CALLED"); //gets called

    LIFECYCLE_HOOKS.forEach(hook => {
      const original = constructor.prototype[hook];

      constructor.prototype[hook] = function(...args) {
        lifecycleLogger.info(`${hook}`, ...args);
        original.apply(this, args);
      };
    });
  };
}

I also have the following unit test:

import { LoggerFactory } from './logger-factory.service';

describe('LoggerFactory', () => {
  localStorage.setItem('FACTORY_LOG_LEVEL', 'WARN');
  const LOGGER_NAME = 'unit.testing.name';
  const logger: any = LoggerFactory.getLogger(LOGGER_NAME);

  it('should provide a logger', () => {
    expect(logger).toBeDefined(logger);
  });

  it('should have the correct name', () => {
    expect(logger.context.name).toEqual(LOGGER_NAME);
  });

  it('should allow for localStorage log level overrides', () => {
    expect(logger.getLevel().name).toEqual('WARN');
  });
});

My problem is that even though I'm never calling the NgLifecycleLog() method, it gets called. This is a problem because I'm trying to use LoggerFactory instead of console statements in it. When I run the unit test, a call to NgLifecycleLog() is made this causes an instance of LoggerFactory to be created when I am not expecting it to.

Why is this called? I've tried doing fdescribe on the tests to make sure this is the only thing being run and even then, that doesn't fix it.

Body:
Class decorators are executed once, when decorated class is defined. If decorated class was included in test bundle, decorator function will be called.

If decorator function produces side effects or involves other units (this may affect unit tests), it should be refactored.

In this case a decorator patches class prototype methods:

const lifecycleLogger = LoggerFactory.getLogger(NAME);

LIFECYCLE_HOOKS.forEach(hook => {
  const original = constructor.prototype[hook];

  constructor.prototype[hook] = function(...args) {
    lifecycleLogger.info(`${hook}`, ...args);
    original.apply(this, args);
  };
});

lifecycleLogger should be moved from the place where it is called on class decoration to the places where it is actually used:

LIFECYCLE_HOOKS.forEach(hook => {
  const original = constructor.prototype[hook];

  constructor.prototype[hook] = function(...args) {
    const lifecycleLogger = LoggerFactory.getLogger(NAME);
    lifecycleLogger.info(`${hook}`, ...args);
    original.apply(this, args);
  };
});


来源: stackexchange

问:
Is there a way to replay a sound from the beginning using AVAudioPlayerNode?
I have a bunch audio nodes set up as so

```<code>var audioPlayers = [AVAudioPlayerNode]()

var engine = AVAudioEngine()

var player = AVAudioPlayerNode()

@IBAction func key(_ sender: UIButton) {
        audioPlayers[someindex].play()
}

func createPlayers() {

        for key in constructedArrayOfNotes {
            player = AVAudioPlayerNode()

            player.volume = 0.5

            let reverb = AVAudioUnitReverb()
            reverb.loadFactoryPreset(AVAudioUnitReverbPreset.cathedral)

            reverb.wetDryMix = 50

            let audiopath = Bundle.main.path(forResource: key, ofType: "mp3",inDirectory: directory)!
            let url = NSURL.fileURL(withPath: audiopath)

            do {
                let file = try! AVAudioFile.init(forReading: url)
                let buffer = AVAudioPCMBuffer(pcmFormat: file.processingFormat, frameCapacity: AVAudioFrameCount(file.length))
                try file.read(into: buffer!)
                engine.attach(player)
                engine.attach(reverb)

                engine.connect(player, to: reverb, format: buffer!.format)
                engine.connect(reverb, to: engine.mainMixerNode, format: buffer!.format)
                player.scheduleFile(file, at: nil, completionHandler: nil)

                audioPlayers.append(player)
            } catch {
                print("error")
            }

        }

}

override func viewDidLoad() {

    createPlayers()
    engine.prepare()
    try! engine.start()

    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}
</code>```

Is there a way for me to replay an audio file that is stored in an AVAudioPlayerNode from the beginning? Currently when I press the IBAction the sound plays but I'm not able to replay it. I'm trying to do the equivalent of AVAudioPlayer.starttime = 0

答:
To answer the question you're asking:

AVAudioPlayerNode doesn't have a seek function, you have to schedule the file again.

One clean way to do it is to just hold references to the audio files as you create them.  Then, in your key function reschedule the file and  play.

```<code>var audioPlayers = [AVAudioPlayerNode]()
var audioFiles = [AVAudioFile]() // Populate in same loop you create the players.

@IBAction func key(_ sender: UIButton) {
    let player = audioPlayers[sender.tag]
    let audioFile = audioFiles[sender.tag]
    player.scheduleFile(audioFile, at: nil, completionHandler: nil)
    player.play()
}
</code>```

To offer advice based on assumption :)

With a key function that is the target of a button, I'm assuming that you want to play different audio files when buttons are pressed.  If you don't mind there being a little lag from the time you press the button until the time audio starts playing,  or, if you're dealing with really long audio files, then your current approach is fine.  However, if an unpredictable lag time isn't acceptable, you have a few options.

Schedule audio AVAudioBuffers instead of files, there is much less of a lag time when starting playback.  You would use the same approach I outlined above, but instead of storing the AVAudioFile and scheduling, store and schedule the AVAudioBuffer.

If you are making a pad or keyboard style sampler, you need to get the lag down to the absolute minimum.  AVAudioUnitSampler is ideal for this.  It's capable of achieving very low latency audio and it can be configured to map files to keys.  It's a little more difficult to set up, but well worth the effort if timing is important.

ContentLicense: CC BY-SA 3.0

Body:
I have a bunch audio nodes set up as so

var audioPlayers = [AVAudioPlayerNode]()

var engine = AVAudioEngine()

var player = AVAudioPlayerNode()

@IBAction func key(_ sender: UIButton) {
        audioPlayers[someindex].play()
}

func createPlayers() {

        for key in constructedArrayOfNotes {
            player = AVAudioPlayerNode()

            player.volume = 0.5

            let reverb = AVAudioUnitReverb()
            reverb.loadFactoryPreset(AVAudioUnitReverbPreset.cathedral)

            reverb.wetDryMix = 50

            let audiopath = Bundle.main.path(forResource: key, ofType: "mp3",inDirectory: directory)!
            let url = NSURL.fileURL(withPath: audiopath)

            do {
                let file = try! AVAudioFile.init(forReading: url)
                let buffer = AVAudioPCMBuffer(pcmFormat: file.processingFormat, frameCapacity: AVAudioFrameCount(file.length))
                try file.read(into: buffer!)
                engine.attach(player)
                engine.attach(reverb)

                engine.connect(player, to: reverb, format: buffer!.format)
                engine.connect(reverb, to: engine.mainMixerNode, format: buffer!.format)
                player.scheduleFile(file, at: nil, completionHandler: nil)

                audioPlayers.append(player)
            } catch {
                print("error")
            }

        }

}

override func viewDidLoad() {

    createPlayers()
    engine.prepare()
    try! engine.start()

    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
}

Is there a way for me to replay an audio file that is stored in an AVAudioPlayerNode from the beginning? Currently when I press the IBAction the sound plays but I'm not able to replay it. I'm trying to do the equivalent of AVAudioPlayer.starttime = 0

Body:
To answer the question you're asking:

AVAudioPlayerNode doesn't have a seek function, you have to schedule the file again.

One clean way to do it is to just hold references to the audio files as you create them.  Then, in your key function reschedule the file and  play.

var audioPlayers = [AVAudioPlayerNode]()
var audioFiles = [AVAudioFile]() // Populate in same loop you create the players.

@IBAction func key(_ sender: UIButton) {
    let player = audioPlayers[sender.tag]
    let audioFile = audioFiles[sender.tag]
    player.scheduleFile(audioFile, at: nil, completionHandler: nil)
    player.play()
}

To offer advice based on assumption :)

With a key function that is the target of a button, I'm assuming that you want to play different audio files when buttons are pressed.  If you don't mind there being a little lag from the time you press the button until the time audio starts playing,  or, if you're dealing with really long audio files, then your current approach is fine.  However, if an unpredictable lag time isn't acceptable, you have a few options.

Schedule audio AVAudioBuffers instead of files, there is much less of a lag time when starting playback.  You would use the same approach I outlined above, but instead of storing the AVAudioFile and scheduling, store and schedule the AVAudioBuffer.

If you are making a pad or keyboard style sampler, you need to get the lag down to the absolute minimum.  AVAudioUnitSampler is ideal for this.  It's capable of achieving very low latency audio and it can be configured to map files to keys.  It's a little more difficult to set up, but well worth the effort if timing is important.


问:
Add field information to file before upload to sharepoint via microsoft-graph
I'm using the c# client library.

When I upload a file, I want to be able to set one of the Fields (SharePoint column) for that file.
I've tried to update the FieldValueSet from the DriveItem.ListItem that is returned after a call to PutAsync<DriveItem>(filestream) Like this

```<code>var newfile = await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[mySubFolderId]
    .ItemWithPath("newFile.txt")
    .Content
    .Request()
    .PutAsync<DriveItem>(fs);

var li = await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[newifle.Id]
    .ListItem
    .Request()
    .GetAsync();

li.Fields.AdditionalData.Add("Title", "My New File Title");

await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[newifle.Id]
    .ListItem
    .Request()
    .UpdateAsync(li);
</code>```

But I get this exception:

ServiceException Field 'id' is not recognised

The above requires 3 calls to the API, but I cant see a way to add the Field when the file is uploaded in one call either.

Updated information as requested -

If I try to set only 1 field then the 'id' still appears in the JSON. Here is the actual code and the 'cleaned' JSON

```<code>    var fs = new FileStream(@"c:\temp\TestImage.jpg", FileMode.Open);
    var newfile = await gClient.Sites[SPSiteId]
      .Drives[LibraryId]
      .Root
      .ItemWithPath("TestImage.jpg")
      .Content
      .Request()
      .PutAsync<DriveItem>(fs);
    var li = await gClient.Sites[SPSiteId]
      .Drives[LibraryId]
      .Items[newifle.Id]
      .ListItem
      .Request()
      .GetAsync();
   var d = new Dictionary<string, object>();
   d.Add("Title", "This should be the title");
   li.Fields.AdditionalData = d;

    await gClient.Sites[SPSiteId]
      .Drives[LibraryId]
      .Items[newifle.Id]
      .ListItem.Request()
      .UpdateAsync(li);
</code>```

First Call:

PUT /v1.0/sites/xxxxxx.sharepoint.com,af844170-6c96-448b-bb75-b1144fa09f3c,d3904f65-6367-4071-9201-e96ea7c3c5d7/drives/b!cEGEr5Zsi0S7dbEUT6CfPGVPkNNnY3FAkgHpbqfDxdeiLjGMWnChSroudPhjGXRg/root:/TestImage.jpg:/content HTTP/1.1

Second Call:

GET /v1.0/sites/xxxxxx.sharepoint.com,af844170-6c96-448b-bb75-b1144fa09f3c,d3904f65-6367-4071-9201-e96ea7c3c5d7/drives/b!cEGEr5Zsi0S7dbEUT6CfPGVPkNNnY3FAkgHpbqfDxdeiLjGMWnChSroudPhjGXRg/items/01QX3GBJL3RSNVFPDYGBG2FKKARXI7TSBV/listItem HTTP/1.1

Third Call (Response is HTTP 400 Bad Request):

PATCH /v1.0/sites/xxxxx.sharepoint.com,af844170-6c96-448b-bb75-b1144fa09f3c,d3904f65-6367-4071-9201-e96ea7c3c5d7/drives/b!cEGEr5Zsi0S7dbEUT6CfPGVPkNNnY3FAkgHpbqfDxdeiLjGMWnChSroudPhjGXRg/items/01QX3GBJL3RSNVFPDYGBG2FKKARXI7TSBV/listItem HTTP/1.1

答:
When you're updating a record, you don't pass in the entire object. Instead, pass in only the fields you want to change:

var li = new ListItem();
li.Fields.AdditionalData.Add("Title", "My New File Title");
await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[newifle.Id]
    .ListItem
    .Request()
    .UpdateAsync(li);
```

When you pass in the full object, you're passing in several read-only properties. Microsoft Graph will assume any values you specify should be applied and fail if any of those values target a read-only property.

Body:
I'm using the c# client library.

When I upload a file, I want to be able to set one of the Fields (SharePoint column) for that file.
I've tried to update the FieldValueSet from the DriveItem.ListItem that is returned after a call to PutAsync<DriveItem>(filestream) Like this

var newfile = await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[mySubFolderId]
    .ItemWithPath("newFile.txt")
    .Content
    .Request()
    .PutAsync<DriveItem>(fs);

var li = await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[newifle.Id]
    .ListItem
    .Request()
    .GetAsync();

li.Fields.AdditionalData.Add("Title", "My New File Title");

await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[newifle.Id]
    .ListItem
    .Request()
    .UpdateAsync(li);

But I get this exception:

ServiceException Field 'id' is not recognised

The above requires 3 calls to the API, but I cant see a way to add the Field when the file is uploaded in one call either.

Updated information as requested -

If I try to set only 1 field then the 'id' still appears in the JSON. Here is the actual code and the 'cleaned' JSON

    var fs = new FileStream(@"c:\temp\TestImage.jpg", FileMode.Open);
    var newfile = await gClient.Sites[SPSiteId]
      .Drives[LibraryId]
      .Root
      .ItemWithPath("TestImage.jpg")
      .Content
      .Request()
      .PutAsync<DriveItem>(fs);
    var li = await gClient.Sites[SPSiteId]
      .Drives[LibraryId]
      .Items[newifle.Id]
      .ListItem
      .Request()
      .GetAsync();
   var d = new Dictionary<string, object>();
   d.Add("Title", "This should be the title");
   li.Fields.AdditionalData = d;

    await gClient.Sites[SPSiteId]
      .Drives[LibraryId]
      .Items[newifle.Id]
      .ListItem.Request()
      .UpdateAsync(li);

First Call:

PUT /v1.0/sites/xxxxxx.sharepoint.com,af844170-6c96-448b-bb75-b1144fa09f3c,d3904f65-6367-4071-9201-e96ea7c3c5d7/drives/b!cEGEr5Zsi0S7dbEUT6CfPGVPkNNnY3FAkgHpbqfDxdeiLjGMWnChSroudPhjGXRg/root:/TestImage.jpg:/content HTTP/1.1

Second Call:

GET /v1.0/sites/xxxxxx.sharepoint.com,af844170-6c96-448b-bb75-b1144fa09f3c,d3904f65-6367-4071-9201-e96ea7c3c5d7/drives/b!cEGEr5Zsi0S7dbEUT6CfPGVPkNNnY3FAkgHpbqfDxdeiLjGMWnChSroudPhjGXRg/items/01QX3GBJL3RSNVFPDYGBG2FKKARXI7TSBV/listItem HTTP/1.1

Third Call (Response is HTTP 400 Bad Request):

PATCH /v1.0/sites/xxxxx.sharepoint.com,af844170-6c96-448b-bb75-b1144fa09f3c,d3904f65-6367-4071-9201-e96ea7c3c5d7/drives/b!cEGEr5Zsi0S7dbEUT6CfPGVPkNNnY3FAkgHpbqfDxdeiLjGMWnChSroudPhjGXRg/items/01QX3GBJL3RSNVFPDYGBG2FKKARXI7TSBV/listItem HTTP/1.1

Body:
When you're updating a record, you don't pass in the entire object. Instead, pass in only the fields you want to change:

var li = new ListItem();
li.Fields.AdditionalData.Add("Title", "My New File Title");
await gClient
    .Sites[mySIteId]
    .Drives[myDriveId]
    .Items[newifle.Id]
    .ListItem
    .Request()
    .UpdateAsync(li);

When you pass in the full object, you're passing in several read-only properties. Microsoft Graph will assume any values you specify should be applied and fail if any of those values target a read-only property.


问:
Counting days between two dates Y/m/d returns wrong number
I'm trying to count the days between 2 dates. It goes well if both dates are in the same month but not if they are in different.
Here is an example where it returns the correct number(1 day):

```<code>var oneDay = 24*60*60*1000;
var firstDate = new Date(2017,11,29);
var secondDate = new Date(2017,11,30);
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
console.log(diffDays);
</code>```

Here is another example. In this case counting the days between last day of november and the 1st day of december, that should be 1 but returns 2

```<code>var oneDay = 24*60*60*1000;
var firstDate = new Date(2017,11,30);
var secondDate = new Date(2017,12,1);
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
console.log(diffDays);
</code>```

I have observed that it returns wrong number if the months are different and if one or both months are conformed by less than 31 days, it adds the number of days missing from the month(s) that have less that 31, in this case 1 because november has 30 days and december 31, 1 + 1(missing days) = 2.
Any Idea of how to get it right is very welcomed.

答: Your rounding function is likely what is causing the issue. Try Math.floor instead to round down, and this will likely solve your problem.

Body:
I'm trying to count the days between 2 dates. It goes well if both dates are in the same month but not if they are in different.
Here is an example where it returns the correct number(1 day):

var oneDay = 24*60*60*1000;
var firstDate = new Date(2017,11,29);
var secondDate = new Date(2017,11,30);
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
console.log(diffDays);

Here is another example. In this case counting the days between last day of november and the 1st day of december, that should be 1 but returns 2

var oneDay = 24*60*60*1000;
var firstDate = new Date(2017,11,30);
var secondDate = new Date(2017,12,1);
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));
console.log(diffDays);

I have observed that it returns wrong number if the months are different and if one or both months are conformed by less than 31 days, it adds the number of days missing from the month(s) that have less that 31, in this case 1 because november has 30 days and december 31, 1 + 1(missing days) = 2.
Any Idea of how to get it right is very welcomed.


问:
Create an empty file on FTP server in Java
I need some Java way alike bash touch-command on FTP – create an empty file on FTP server with org.apache.commons.net.ftp.FTPClient (or another library).

答:
Upload an empty "in-memory file", like this:</p>

```<code>InputStream bin = ByteArrayInputStream(new byte[0]);
ftpClient.storeFile("/remote/path/emptyfile", bin);
</code>```

ContentLicense: CC BY-SA 4.0

Body:
Upload an empty "in-memory file", like this:

InputStream bin = ByteArrayInputStream(new byte[0]);
ftpClient.storeFile("/remote/path/emptyfile", bin);


问:
How to build a portable class library without Visual Studio?
I'm trying to build a portable library project on a TFS server and I've got the following error:

"The imported project "C:\Program Files (x86)\MSBuild\Microsoft\Portable\v4.6\Microsoft.Portable.CSharp.targets" was not found. Confirm that the path in the  declaration is correct, and that the file exists on disk"

It's true, I don't have a Portable directory in MSBuild/Microsoft on the server. I have it on my developer computer, so I guess if I install Visual Studio it will work but I don't want to. I've installed the build tools on the server, with all the available UWP features but I still don't have this Portable directory.

答: In general, your build server should consist of the same software configuration as a developer workstation. Install Visual Studio. It does not consume a license. </p>


问:
Uploading a csv into Codeigniter
Has anyone else had trouble uploading a csv file into Codeigniter? I'm getting a pretty annoying "The filetype you are attempting to upload is not allowed." error, even though I've quite explicitly set the upload type. Here's my code (should be fairly standard stuff):

```<code>    function doUpload() {

    $config['upload_path'] = 'uploads/';
    $config['allowed_types'] = 'text/plain|text/csv|csv';
    $config['max_size'] = '5000';
    $config['file_name'] = 'upload' . time();

    $this->load->library('upload', $config);

    if(!$this->upload->do_upload()) echo $this->upload->display_errors();
    else {
        $file_info = $this->upload->data();
        $csvfilepath = "uploads/" . $file_info['file_name'];
        $this->addfromcsv($csvfilepath);

    }

}
</code>```

I tried to cover all the bases in my allowed types - maybe I missed one?
Thanks for any help with this!

答:
Unluckily there is no official specification, so there's quite a lot of them: the most popular among those that are missing are,

```<code>text/comma-separated-values|application/csv|application/excel|application/vnd.ms-excel|application/vnd.msexcel|text/anytext
</code>```

It's highly unlikely you'll meet another one.

ContentLicense: CC BY-SA 2.5

Title: Uploading a csv into Codeigniter

Body:
Has anyone else had trouble uploading a csv file into Codeigniter? I'm getting a pretty annoying "The filetype you are attempting to upload is not allowed." error, even though I've quite explicitly set the upload type. Here's my code (should be fairly standard stuff):

    function doUpload() {

    $config['upload_path'] = 'uploads/';
    $config['allowed_types'] = 'text/plain|text/csv|csv';
    $config['max_size'] = '5000';
    $config['file_name'] = 'upload' . time();

    $this->load->library('upload', $config);

    if(!$this->upload->do_upload()) echo $this->upload->display_errors();
    else {
        $file_info = $this->upload->data();
        $csvfilepath = "uploads/" . $file_info['file_name'];
        $this->addfromcsv($csvfilepath);

    }

}

I tried to cover all the bases in my allowed types - maybe I missed one?
Thanks for any help with this!

Body:
Unluckily there is no official specification, so there's quite a lot of them: the most popular among those that are missing are,

text/comma-separated-values|application/csv|application/excel|application/vnd.ms-excel|application/vnd.msexcel|text/anytext

It's highly unlikely you'll meet another one.


问:
Aborting an ongoing Firebase database request
I was wondering if there is any way to cancel/abort a Firebase Realtime Database request when it hasn't returned any results yet.

Consider the following:

1) User selects an item from a list
2) (Web) app makes a request to retrieve some messages or other data for that item
3) The user navigates back and selects a different item
4) The Firebase request returns with results for the wrong item

A regular xhr request can be aborted. A timeout (setTimeout) can be cleared. Is there any way to abort/cancel an ongoing firebase request?

Example:

```<code>var request;
// ..

if (request) { abort(request); request = null; }
request = firebase.database().ref("item1/").once("value", callback);
</code>```

PS: this question is about the database but I guess this would be really handy for most firebase services?

答:
There is no way to abort a read operation.

If you don't want you app to use the data anymore, you can detach the listener by calling off().

This doesn't just work for listeners you register using .on() but also works for .once().

Example:

```<code>firebase.db.ref("/item1").once("value", function(snap) { console.log("1: ", snap.val()); });
firebase.db.ref("/item1").off();
firebase.db.ref("/item2").once("value", function(snap) { console.log("2: ", snap.val()); });
</code>```

Prints the following in the console:

2:  { ... }

In other words: the callback from the first line never gets called (unless it returns a result before .off() is called)

Body:
I was wondering if there is any way to cancel/abort a Firebase Realtime Database request when it hasn't returned any results yet.

Consider the following:

1) User selects an item from a list
2) (Web) app makes a request to retrieve some messages or other data for that item
3) The user navigates back and selects a different item
4) The Firebase request returns with results for the wrong item

A regular xhr request can be aborted. A timeout (setTimeout) can be cleared. Is there any way to abort/cancel an ongoing firebase request?

Example:

var request;
// ..

if (request) { abort(request); request = null; }
request = firebase.database().ref("item1/").once("value", callback);

PS: this question is about the database but I guess this would be really handy for most firebase services?

Body:
There is no way to abort a read operation.

If you don't want you app to use the data anymore, you can detach the listener by calling off().

This doesn't just work for listeners you register using .on() but also works for .once().

Example:

firebase.db.ref("/item1").once("value", function(snap) { console.log("1: ", snap.val()); });
firebase.db.ref("/item1").off();
firebase.db.ref("/item2").once("value", function(snap) { console.log("2: ", snap.val()); });

Prints the following in the console:

2:  { ... }

In other words: the callback from the first line never gets called (unless it returns a result before .off() is called)


问:
Finding k xonnected vertices with wight sum bellow t
I have an undirected graph G(E,V) with weights on the vertices. I need to find every k connected vertices so that the sum of their weight is smaller then a number t.
The major problem I have is dealing with circles.
Will be happy to get any ideas ... Even if its not a complete algorithn

-----edit-----

so far i had the following ideas (which are not working)..

I know that each componnent has a spreading tree, when I look on the root (R) of that tree (tree of k vertices with sum under t) then I have the following options: R has a son and he is a root for such tree with k-1 vertices || R has two sons one is the root of tree with k-2 and another son root of the tree with 1 vertex(the son itself) and so on...
so to find R I wanted to use dynamic programing. first ill find for each v in V the minimum tree with 1 vertex that v is its root. then 2 .. and by the idea above ill find the rest.
the problem is, example: if R has only one son u and the minimum tree of k-1 verticees that u is its root contains R, than it turns out that R is not the root of tree of k vertices .. when there is the option that u is the root of k-1 tree (not minimal) that doesnt contains R and W(T(k-1))+W(R) < t...

I tried dealing with this problem by building BFS tree with k layers for eac v in V, but then I think im loosing options because the BFS tree dosent contains all edges.

3.thought about maybe to tranform this problem to max flow problem some how but couldent see how to do it.

答:
You can use breadth first search and stop processing nodes when the distance with the sum of weights to the source (denoted by 's') is greater or equal 't'.

Something along these lines (Java style code):

```<code>private void bfs(Graph G, int s) {
    Queue<Integer> q = new Queue<>();
    for (int v = 0; v < G.V(); v++)
        distTo[v] = INFINITY;
    distTo[s] = 0;
    marked[s] = true;
    q.enqueue(s);

    while (!q.isEmpty()) {
        int v = q.dequeue();

        for (int w : G.adj(v)) {
            if (!marked[w] && distTo[v] + weights[v] < t) { // preventing going beyond accumulated weight 't'
                distTo[w] = distTo[v] + weights[v];
                marked[w] = true;
                q.enqueue(w);
                edgeTo[w] = v;
            }
        }
    }
}
</code>```

The fields I have used above are mostly arrays and their index should be a vertex v (assuming that all nodes in the graph are integer numbers from 0 to n - 1):

```<code>private boolean[] marked;  // marked[v] = is node v already visited ?
private int[] edgeTo;      // edgeTo[v] = previous edge on shortest s-v path
private int[] distTo;      // distTo[v] = number of edges shortest weights s-v path
private int[] weights;     // weights[v] = weight of v
</code>```

After processing the bfs routine all marked nodes should have a distance less than t.

You can deal with circles by marking the nodes, in order not to re-visit them.

Body:
You can use breadth first search and stop processing nodes when the distance with the sum of weights to the source (denoted by 's') is greater or equal 't'.

Something along these lines (Java style code):

private void bfs(Graph G, int s) {
    Queue<Integer> q = new Queue<>();
    for (int v = 0; v < G.V(); v++)
        distTo[v] = INFINITY;
    distTo[s] = 0;
    marked[s] = true;
    q.enqueue(s);

    while (!q.isEmpty()) {
        int v = q.dequeue();

        for (int w : G.adj(v)) {
            if (!marked[w] && distTo[v] + weights[v] < t) { // preventing going beyond accumulated weight 't'
                distTo[w] = distTo[v] + weights[v];
                marked[w] = true;
                q.enqueue(w);
                edgeTo[w] = v;
            }
        }
    }
}

The fields I have used above are mostly arrays and their index should be a vertex v (assuming that all nodes in the graph are integer numbers from 0 to n - 1):

private boolean[] marked;  // marked[v] = is node v already visited ?
private int[] edgeTo;      // edgeTo[v] = previous edge on shortest s-v path
private int[] distTo;      // distTo[v] = number of edges shortest weights s-v path
private int[] weights;     // weights[v] = weight of v

After processing the bfs routine all marked nodes should have a distance less than t.

You can deal with circles by marking the nodes, in order not to re-visit them.


问:
Using Delphi data-aware components - pros and cons
I want to know your opinion about using data-aware components in projects. Which are the 'strength' and 'weak' points of developing applications(win32 and web), by using Delphi and data-aware components(from Delphi's standard suite or third-party)?

Using FireBird I've worked a lot with IBObjects, which are a mature suite of components and worked very well.

But there are also a lot of other RDBMS (MySQL, MSSQL, DB2, Oracle, SQLite, Nexus, Paradox, Interbase, FireBird etc). If you have developed big projects, on which you've used a lot data-aware  components please answer with the database type and data-aware components suite name.

I'm also interested on DB2 (AS400). What components have you used with success, or which components are really a pain to work with?

答:
Having tried both data-aware and non data-aware style of Delphi applications I'm back in the data-aware component camp these days. It takes a bit of work and discipline to correctly layer the code but it's still quicker than doing everything by hand using non data-aware controls.

A few of my tips for data-aware component usage are

Don't just rewrite FishFact on a larger scale. Put some thought into your design.

Don't use a TDataModule, use many TDataModules each responsible for just a small aspect of your applications data.

TDatasets belong on TDataModules, while TDataSources belong on TForms (unless used for master/detail relationships).

Use in-memory datasets such as the DataSnap TClientDataSet.

Your ClientDataSets don't have to mirror your database tables exactly. DataSnap allows you massage your data structures in memory so you can produce datasets tailored for specific purposes. Specifically you can do things like

Joining two or more tables into the one editable dataset

Denormalizing master detail table structures, can simplify your UI code sometimes.

Create in-memory only fields (like calculated fields but you can write to them also)

TClientDataSet nested tables are useful but not the only way to express master detail relationships. Sometimes it's better to do it the old way with two independent TClientDataSets joined through a TDataSource.


问:
How to filter chrome's devtool console history
In bash, I use the history-search-forward and history-search-backward feature to allow me to type in a few characters of the command I want to run, then press up arrow to cycle through items in my history that match those characters.

I want the same thing for the chrome devtool console. I often use up arrow to cycle through my history, but there doesn't seem to be a way to filter it. Does anybody have a clever solution?

[Just a note that command history matching has improved a lot in recent versions of Chrome. It's not exactly how I would like it, but it's pretty good.]

答:
Try this: (based on How to remove all recent console command)

Open Chrome Dev Tools on the Chrome Dev Tools window (as per post above) by following steps 1-3 on the first answer (by Rob W).  Don't do step 4 or you'll wipe out your history!

Run this command in the new Dev Tools console: JSON.parse(localStorage.getItem('consoleHistory')).filter(function(item){ return ~item.indexOf('indexedDB');})

Replace "indexedDB" with whatever it is you want to filter on.

TL;DR

Chrome Dev Tools is technically just another browser window.

The LocalStorage of the original Dev Tools is for the site you are browsing.

By opening Dev Tools on the Dev Tools, gives you the LocalStorage for the Dev Tools window and thus gives you access to the consoleHistory.

localStorage.getItem('consoleHistory') gives you a string of an Array, so you need to parse it (i.e. JSON.parse()) back into an Array so you can filter it.

The ~ in front of ~item.indexOf('indexedDB') is a bitwise shortcut for item.indexOf('indexedDB') > 0


问:
What is this syntax: "Component.For<IOutput>()"?
I'm finding code examples all over the place in IoC and DI discussions that use < and > in their syntax, usually at the end of what looks like a method call.

Can someone

Tell me what language this is, and

Explain this syntax enough to help me understand the code examples, so I can make sure I understand the underlying principles.

答: The angle brackets are used to denote the type to use. It ensures compile time safety. This is the syntax used for generics (c#).</p>


问:
swift how to push back to navigation view control
I have several view controllers and they are very complexed.

MainVC (embed with tab bar controller)

FriendListVC

ChatRoomUpperVC (embed with navigation view controller)

ChatRoomVC (NavigationViewController with embed in ChatRoomUpperVC) (only shows the tab bar)

ChatRoomQuestionVC (pushed from ChatRoomVC) (only shows the navigation bar)

MatchedWaitVC (pushed from ChatRoomQuestionVC) (hide both tab and navigation bars)

ChatVC (pushed from MatchedWaitVC) (only shows the navigation bar)

SettingVC

What I have to do is when I click the back button from the ChatVC, I should back to ChatRoomVC and show the tab bar on the bottom only.

I tried the code below but it shows the black screen and there is no tar bar neither.

```<code>    override func willMove(toParentViewController parent: UIViewController?) {
        if parent == nil
        {
            var viewControllers = navigationController?.viewControllers
            viewControllers?.removeLast(3)
            navigationController?.setViewControllers(viewControllers!, animated: true)
            self.navigationController?.isNavigationBarHidden = true
            self.tabBarController?.tabBar.isHidden = false
        }
    }
</code>```

答:
I guess you can use following hack to achieve what you want. In the viewDidLoad method of the ChatVC do:

```<code>override func viewDidLoad() {
    super.viewDidLoad()
    if let root = navigationController?.viewControllers.first {
        navigationController?.viewControllers = [root, self]
    }
}
</code>```

This will remove the inbetween view controllers that are between ChatVC and ChatRoomVC. Now popping back (e.g. using the standard back button, or swiping from the left edge of the screen) will jump back directly to the ChatRoomVC.

EDIT

To show the tabBar again in the ChatRoomVC, add this to the viewDidAppear:

```<code>override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.tabBarController?.tabBar.isHidden = false
}
</code>```

This will ensure that as soon as ChatRoomVC appears on the screen, its tabBar will be presented, too.

Body:
I have several view controllers and they are very complexed.

MainVC (embed with tab bar controller)

FriendListVC

ChatRoomUpperVC (embed with navigation view controller)

ChatRoomVC (NavigationViewController with embed in ChatRoomUpperVC) (only shows the tab bar)

ChatRoomQuestionVC (pushed from ChatRoomVC) (only shows the navigation bar)

MatchedWaitVC (pushed from ChatRoomQuestionVC) (hide both tab and navigation bars)

ChatVC (pushed from MatchedWaitVC) (only shows the navigation bar)

SettingVC

What I have to do is when I click the back button from the ChatVC, I should back to ChatRoomVC and show the tab bar on the bottom only.

I tried the code below but it shows the black screen and there is no tar bar neither.

    override func willMove(toParentViewController parent: UIViewController?) {
        if parent == nil
        {
            var viewControllers = navigationController?.viewControllers
            viewControllers?.removeLast(3)
            navigationController?.setViewControllers(viewControllers!, animated: true)
            self.navigationController?.isNavigationBarHidden = true
            self.tabBarController?.tabBar.isHidden = false
        }
    }

Body:
I guess you can use following hack to achieve what you want. In the viewDidLoad method of the ChatVC do:

override func viewDidLoad() {
    super.viewDidLoad()
    if let root = navigationController?.viewControllers.first {
        navigationController?.viewControllers = [root, self]
    }
}

This will remove the inbetween view controllers that are between ChatVC and ChatRoomVC. Now popping back (e.g. using the standard back button, or swiping from the left edge of the screen) will jump back directly to the ChatRoomVC.

EDIT

To show the tabBar again in the ChatRoomVC, add this to the viewDidAppear:

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    self.tabBarController?.tabBar.isHidden = false
}

This will ensure that as soon as ChatRoomVC appears on the screen, its tabBar will be presented, too.


问:
Automatically generating multiple choice quizzes on google forms
I am a teacher and need to create lots of multiple choice quizzes like this for my students.

You will see that each multiple choice question has exactly the same format - a question to be uploaded as an image and then followed by 4 multiple choice options - A, B, C and D.

My question is, is there any way to automate this process?

Each batch of questions are inside a googledrive folder and are named '1.png', '2.png', '3.png', etc - these are to be uploaded as images on the google form.

In a separate folder, I have a googlesheet listing all the answers to each question, it looks like this.

So the numbers that match with the answers (letters) in the spreadsheet correspond to the image files (eg. the first row of the spreadsheet above shows that the answer to question 1.png is A)

In a separate folder, I have another googlesheet, with feedback for both incorrect and correct answers which looks like this. Not all questions have feedback.

Is there anyway to automatically generate quizzes from these googlesheets and png files?

Thanks for taking the time to read through all this, and special thanks if you are able to suggest a solution?

答:
Here's a solution to a questioner that wanted to randomly select a given number of questions from a question bank.  This doesn't utilize google forms but rather it uses html forms.

Here's the code (your welcome to adapt it):
I had some questions on the code and corrected and problem and went in and updated the code.  It's a little more organized and a bit easier to follow...I hope.

Code.gs:

```<code>function onOpen() {
    SpreadsheetApp.getUi().createMenu('Questions Menu')
      .addItem('Questions', 'launchQuestionsDialog')
      .addToUi();
}
</code>```

question.gs

```<code>function getQuestions() {
  var ss=SpreadsheetApp.getActive();
  var cpData=getCpData();
  var qnum=cpData.qNum;
  var qa=getQAndA();
  var qi=getAnswerIndexes();
  var html='';
  var clr=['#f6d1ac','#c5e9bd'];
  for(var i=0;i<qa.length;i++) {
    html+=Utilities.formatString('<div id=d%s style="font-weight:bold;background-color:%s;padding:5px;"><span id="q%s">%s</span><input type="hidden" value="%s" class="hiding" />',qa[i][0],clr[i % 2],qa[i][0],qa[i][1],qa[i][0]);
    html+=Utilities.formatString('<input type="hidden" value="%s" class="hiding" />',qa[i][0]);
    for(var j=qi.firstIdx;j<=qi.lastIdx;j++) {
      if(qa[i][j]) {
        html+=Utilities.formatString('<br /><input type="radio" name="n%s" value="%s" />%s',qa[i][0],qa[i][j],qa[i][j]);
      }
    }
    html+='</div>'
  }
  html+='<div id="controls"><br /><input type="button" value="Submit" onClick="recordData();" /></div>';
  return {html:html}
}

function launchQuestionsDialog() {
  var userInterface=HtmlService.createHtmlOutputFromFile('questions').setWidth(800).setHeight(500);
  SpreadsheetApp.getUi().showModelessDialog(userInterface, "The new Questions");
}

function selectTest() {
  var qA=selectQuestions(5,24);
  Logger.log(qA);
}

function selectQuestionIndexes(n,m) {
  var set=[];
  do {
    var i=Math.floor(Math.random()*(m));
    if(set.indexOf(i)==-1) {
      set.push(i);
    }
  }while(set.length<n);
  return set;
}

function getCpData() {
  var ss=SpreadsheetApp.getActive();
  var cpSh=ss.getSheetByName('ControlPanel');
  var cpRg=cpSh.getDataRange();
  var cpVa=cpRg.getValues();
  var qsrcSh=ss.getSheetByName(cpVa[1][0]);
  var adesSh=ss.getSheetByName(cpVa[1][1]);
  var qnum=cpVa[1][2];
  var cpData={'qSrc':cpVa[1][0],'aDes':cpVa[1][1],'qNum':cpVa[1][2]};
  return cpData;
}

function getAnswerIndexes() {
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getSheetByName(getCpData().qSrc);
  var rg=sh.getRange(1,1,1,sh.getLastColumn());
  var vA=rg.getValues();
  var re=/Answer \d{1,2}/i;
  var fidx=0;
  var lidx=0;
  var first=true;
  vA[0].forEach(function(e,i){if(String(vA[0][i]).match(re))if(first){fidx=i;first=false;}else{lidx=i;}});
  return {'firstIdx':fidx,'lastIdx':lidx};
}

function recordData(responses) {
  if(responses) {
    var ss=SpreadsheetApp.getActive();
    var sheetname=getCpData().aDes;
    var sh=ss.getSheetByName(sheetname);
    var ts=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy HH:mm:ss");
    responses.forEach(function(e,i){e.splice(0,0,ts);sh.appendRow(e)});
  }
  return true;
}

function doGet() {
  return HtmlService.createHtmlOutputFromFile('questions');
}

function getQAndA() {
  var qa=[];
  var cma=',';
  var ss=SpreadsheetApp.getActive();
  var cpData=getCpData();
  var qsrcSh=ss.getSheetByName(cpData.qSrc);
  var qsrcRg=qsrcSh.getRange(2,1,qsrcSh.getLastRow()-1,qsrcSh.getLastColumn());
  var qsrcVa=qsrcRg.getValues();
  var qs=selectQuestionIndexes(cpData.qNum,qsrcVa.length);
  var aIdxs=getAnswerIndexes();
  for(var i=0;i<qsrcVa.length;i++) {
    var qas='';
    if(qs.indexOf(i)>-1) {
      qas+=qsrcVa[i][0] + cma + qsrcVa[i][1];
      for(j=aIdxs.firstIdx;j<=aIdxs.lastIdx;j++) {
        if(qsrcVa[i][j]) {
            qas+= cma + qsrcVa[i][j];
        }
      }
      qa.push(qas.split(cma));
    }
  }
  return qa;
}
</code>```

questions.html:

```<code><!DOCTYPE html>
<html>
<head>
 <!--<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>-->
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
 <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script>
    $(function() {
        google.script.run
        .withSuccessHandler(function(hObj){
          $('#container').html(hObj.html);
        })
        .getQuestions();
      });
    function recordData() {
      var responses=[];
      var cm=',';
      var divs = document.getElementsByTagName("div");
      for(var i=0;i<divs.length;i++) {
        var id=divs[i].getAttribute(['id']);
        var qnum=$('div#' + id + ' ' + 'input.hiding').val();
        //var question=document.getElementById(id).innerHTML;
        var question=$('#q' + qnum ).text();
        var answer=$('input[name="n' + qnum + '"]:checked').val();
        if(id!='controls') {
          if(!answer) {
            window.alert('You did not answer question number ' + Number(i+1) + '. It is a requirement of this survey that all questions must be answered.' );
            return;
          }else {
            var end='is near';
            var s=qnum + cm + question + cm + answer;
            responses.push(s.split(cm));
          }
        }
      }

      google.script.run
      .withSuccessHandler(displayThanks)
      .recordData(responses);
    }
    function displayThanks() {
      var divs = document.getElementsByTagName("div");
      for(var i=0;i<divs.length;i++) {
        divs[i].style.cssText="display:none;text-align:center";
      }
      var elemDiv = document.createElement('div');
      elemDiv.innerHTML="<br /><h1>Thank You For Your Participation in This Survey</h1>";
      document.body.appendChild(elemDiv);
    }
    console.log('My Code');
    </script>
    <style>
    #reply{display:none;}
    #collect{display:block;}
    body  {
    background-image: url("http://myrabridgforth.com/wp-content/uploads/blue-sky-clouds.jpg");
    background-color: #ffffff;
    background-repeat: no-repeat;
    background-position: left bottom;
    }
    </style>
</head>
  <body>
    <div id="container">
    </div>
  </body>
</html>
</code>```

Here's what the various tabs on the spreadsheet look like:

The ControlPanel Tab:

The QuestionBank Tab:

The Test1 Tab:

Hopefully this will be of some value to you.

Body:
Here's a solution to a questioner that wanted to randomly select a given number of questions from a question bank.  This doesn't utilize google forms but rather it uses html forms.

Here's the code (your welcome to adapt it):
I had some questions on the code and corrected and problem and went in and updated the code.  It's a little more organized and a bit easier to follow...I hope.

Code.gs:

function onOpen() {
    SpreadsheetApp.getUi().createMenu('Questions Menu')
      .addItem('Questions', 'launchQuestionsDialog')
      .addToUi();
}

question.gs

function getQuestions() {
  var ss=SpreadsheetApp.getActive();
  var cpData=getCpData();
  var qnum=cpData.qNum;
  var qa=getQAndA();
  var qi=getAnswerIndexes();
  var html='';
  var clr=['#f6d1ac','#c5e9bd'];
  for(var i=0;i<qa.length;i++) {
    html+=Utilities.formatString('<div id=d%s style="font-weight:bold;background-color:%s;padding:5px;"><span id="q%s">%s</span><input type="hidden" value="%s" class="hiding" />',qa[i][0],clr[i % 2],qa[i][0],qa[i][1],qa[i][0]);
    html+=Utilities.formatString('<input type="hidden" value="%s" class="hiding" />',qa[i][0]);
    for(var j=qi.firstIdx;j<=qi.lastIdx;j++) {
      if(qa[i][j]) {
        html+=Utilities.formatString('<br /><input type="radio" name="n%s" value="%s" />%s',qa[i][0],qa[i][j],qa[i][j]);
      }
    }
    html+='</div>'
  }
  html+='<div id="controls"><br /><input type="button" value="Submit" onClick="recordData();" /></div>';
  return {html:html}
}

function launchQuestionsDialog() {
  var userInterface=HtmlService.createHtmlOutputFromFile('questions').setWidth(800).setHeight(500);
  SpreadsheetApp.getUi().showModelessDialog(userInterface, "The new Questions");
}

function selectTest() {
  var qA=selectQuestions(5,24);
  Logger.log(qA);
}

function selectQuestionIndexes(n,m) {
  var set=[];
  do {
    var i=Math.floor(Math.random()*(m));
    if(set.indexOf(i)==-1) {
      set.push(i);
    }
  }while(set.length<n);
  return set;
}

function getCpData() {
  var ss=SpreadsheetApp.getActive();
  var cpSh=ss.getSheetByName('ControlPanel');
  var cpRg=cpSh.getDataRange();
  var cpVa=cpRg.getValues();
  var qsrcSh=ss.getSheetByName(cpVa[1][0]);
  var adesSh=ss.getSheetByName(cpVa[1][1]);
  var qnum=cpVa[1][2];
  var cpData={'qSrc':cpVa[1][0],'aDes':cpVa[1][1],'qNum':cpVa[1][2]};
  return cpData;
}

function getAnswerIndexes() {
  var ss=SpreadsheetApp.getActive();
  var sh=ss.getSheetByName(getCpData().qSrc);
  var rg=sh.getRange(1,1,1,sh.getLastColumn());
  var vA=rg.getValues();
  var re=/Answer \d{1,2}/i;
  var fidx=0;
  var lidx=0;
  var first=true;
  vA[0].forEach(function(e,i){if(String(vA[0][i]).match(re))if(first){fidx=i;first=false;}else{lidx=i;}});
  return {'firstIdx':fidx,'lastIdx':lidx};
}

function recordData(responses) {
  if(responses) {
    var ss=SpreadsheetApp.getActive();
    var sheetname=getCpData().aDes;
    var sh=ss.getSheetByName(sheetname);
    var ts=Utilities.formatDate(new Date(), Session.getScriptTimeZone(), "MM/dd/yyyy HH:mm:ss");
    responses.forEach(function(e,i){e.splice(0,0,ts);sh.appendRow(e)});
  }
  return true;
}

function doGet() {
  return HtmlService.createHtmlOutputFromFile('questions');
}

function getQAndA() {
  var qa=[];
  var cma=',';
  var ss=SpreadsheetApp.getActive();
  var cpData=getCpData();
  var qsrcSh=ss.getSheetByName(cpData.qSrc);
  var qsrcRg=qsrcSh.getRange(2,1,qsrcSh.getLastRow()-1,qsrcSh.getLastColumn());
  var qsrcVa=qsrcRg.getValues();
  var qs=selectQuestionIndexes(cpData.qNum,qsrcVa.length);
  var aIdxs=getAnswerIndexes();
  for(var i=0;i<qsrcVa.length;i++) {
    var qas='';
    if(qs.indexOf(i)>-1) {
      qas+=qsrcVa[i][0] + cma + qsrcVa[i][1];
      for(j=aIdxs.firstIdx;j<=aIdxs.lastIdx;j++) {
        if(qsrcVa[i][j]) {
            qas+= cma + qsrcVa[i][j];
        }
      }
      qa.push(qas.split(cma));
    }
  }
  return qa;
}

questions.html:

<!DOCTYPE html>
<html>
<head>
 <!--<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>-->
 <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
 <link rel="stylesheet" href="//code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
 <script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>
    <script>
    $(function() {
        google.script.run
        .withSuccessHandler(function(hObj){
          $('#container').html(hObj.html);
        })
        .getQuestions();
      });
    function recordData() {
      var responses=[];
      var cm=',';
      var divs = document.getElementsByTagName("div");
      for(var i=0;i<divs.length;i++) {
        var id=divs[i].getAttribute(['id']);
        var qnum=$('div#' + id + ' ' + 'input.hiding').val();
        //var question=document.getElementById(id).innerHTML;
        var question=$('#q' + qnum ).text();
        var answer=$('input[name="n' + qnum + '"]:checked').val();
        if(id!='controls') {
          if(!answer) {
            window.alert('You did not answer question number ' + Number(i+1) + '. It is a requirement of this survey that all questions must be answered.' );
            return;
          }else {
            var end='is near';
            var s=qnum + cm + question + cm + answer;
            responses.push(s.split(cm));
          }
        }
      }

      google.script.run
      .withSuccessHandler(displayThanks)
      .recordData(responses);
    }
    function displayThanks() {
      var divs = document.getElementsByTagName("div");
      for(var i=0;i<divs.length;i++) {
        divs[i].style.cssText="display:none;text-align:center";
      }
      var elemDiv = document.createElement('div');
      elemDiv.innerHTML="<br /><h1>Thank You For Your Participation in This Survey</h1>";
      document.body.appendChild(elemDiv);
    }
    console.log('My Code');
    </script>
    <style>
    #reply{display:none;}
    #collect{display:block;}
    body  {
    background-image: url("http://myrabridgforth.com/wp-content/uploads/blue-sky-clouds.jpg");
    background-color: #ffffff;
    background-repeat: no-repeat;
    background-position: left bottom;
    }
    </style>
</head>
  <body>
    <div id="container">
    </div>
  </body>
</html>

Here's what the various tabs on the spreadsheet look like:

The ControlPanel Tab:

The QuestionBank Tab:

The Test1 Tab:

Hopefully this will be of some value to you.


问:
How do you properly write and use a View subclass in Android?
I am trying to implement one of the solutions found here.

My problem is that I'm not sure if I am implementing and using my subclass correctly.
I am subclassing a WebView here:

```<code>public class myWebView extends WebView{

  public myWebView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
}

  @Override
protected void onSizeChanged(int w, int h, int ow, int oh) {
    // TODO Auto-generated method stub

      scrollTo(xScroll - (widthScroll/2), yScroll - (heightScroll/2));

    super.onSizeChanged(w, h, ow, oh);
}

   }}
</code>```

It should be private but forget that for now.  I have the code inside of one of my activities that has an inner webview in the view hierarchy.  Outside of the onCreate method of that activity.

Inside the onCreate method, I have:myWebView mapImage = (myWebView) findViewById(R.id.mapcroppic);

This gives me a ClassCastException for that call. (Does the xml layout file need to use <myWebView>? Can it?)  How do I use this the correct way?

答:
(Does the xml layout file need to use <myWebView>? Can it?)  How do I use this the correct way?

Yes:

```<code><your.package.name.myWebView
    android:layout_with="blah"/>
</code>```

Well, that works if the myWebView is a public class. If it's an inner one:

```<code><view class="your.package.name.myWebView.YourActivity$myWebView" />
</code>```

Body:
I am trying to implement one of the solutions found here.

My problem is that I'm not sure if I am implementing and using my subclass correctly.
I am subclassing a WebView here:

public class myWebView extends WebView{

  public myWebView(Context context) {
    super(context);
    // TODO Auto-generated constructor stub
}

  @Override
protected void onSizeChanged(int w, int h, int ow, int oh) {
    // TODO Auto-generated method stub

      scrollTo(xScroll - (widthScroll/2), yScroll - (heightScroll/2));

    super.onSizeChanged(w, h, ow, oh);
}

   }}

It should be private but forget that for now.  I have the code inside of one of my activities that has an inner webview in the view hierarchy.  Outside of the onCreate method of that activity.

Inside the onCreate method, I have:myWebView mapImage = (myWebView) findViewById(R.id.mapcroppic);

This gives me a ClassCastException for that call. (Does the xml layout file need to use <myWebView>? Can it?)  How do I use this the correct way?

Body:
(Does the xml layout file need to use <myWebView>? Can it?)  How do I use this the correct way?

Yes:

<your.package.name.myWebView
    android:layout_with="blah"/>

Well, that works if the myWebView is a public class. If it's an inner one:

<view class="your.package.name.myWebView.YourActivity$myWebView" />


问:
how to publish a 3rd party library to support both angular 2 and angular4
I am using a 3rd party library for Angular. Initially it is supported in Angular 2. For the Upgraded versions of Angular(Angular 4 and Angular 5), how will i publish a 3rd party library to support for All versions of Angular?</p>

答:
If the codebase is identical, just publish your library and mention Angular dependencies with ^2.0.0 in your peerDependencies.

If the codebase is different for the different versions of Angular, maintain different versions. I suggest to use the corresponding Angular versions as your version number, so for instance your 2.x version will be for Angular 2, 4.x for Angular 4 and 5.x for Angular 5.

And in your peerDependencies, mention the Angular dependencies with ranges, like >=4.0.0 <5.0.0.


问:
Forgot Admin Password on Postgres (Windows Installation), can't reset
I have a Windows PostgreSQL installation.

According to some posts, there is no default password set for the 'postgres' user yet I can't connect using an empty password string.

I'm receiving this exception when I try to connect:

```<code>Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "postgres"
</code>```

The most relevant tip was this:
https://stackoverflow.com/a/25943227/1005607

```<code>Open  pg_hba.conf
Change md5 -> TRUST
then restart PgAdmin.
</code>```

I tried that and restarted PGAdmin but it still asks me for the password when I try to connect:

The task manager in Windows shows some PostgreSQL processes are running. I can't switch them off.

I have tried this and it failed:

```<code>pg_ctl restart

ERROR:
pg_ctl: no database directory specified and environment variable PGDATA unset

psql.exe postgres
Password: (none)
ERROR:
psql: fe_sendauth: no password supplied
</code>```

How can I reset the default password for user 'postgres'?

答:
Update your pg_hba.conf file to allow for trusted local connections

```<code>[root@server] vim pg_hba.conf
>> local all all         trust
</code>```

then restart your PostgreSQL server

```<code>[user@machine] pg_ctl -D C:\PostgreSQL\data restart    (Windows)
[root@server] service postgresql restart            (Linux)
</code>```

at this point you can connect to your server as postgres user using a local connection without the need to enter a password (omitting the -h parameter when calling the psql command will use a local connection - if you pass -h then this will match the line host all all 0.0.0.0/0 <method> in your pg_hba.conf file)

```<code>[root@server] psql -U postgres
</code>```

You can then alter the postgres user role and set the password to whatever you like using the following command in the psql terminal

```<code>[psql] alter role postgres password <new_password>;
</code>```

Once this is done you can restart your PostgreSQL server again

```<code>[user@machine] pg_ctl -D C:\PostgreSQL\data restart     (Windows)
[root@server] service postgresql restart             (Linux)
</code>```

and at this point your password should be changed to the new password

Body:
I have a Windows PostgreSQL installation.

According to some posts, there is no default password set for the 'postgres' user yet I can't connect using an empty password string.

I'm receiving this exception when I try to connect:

Caused by: org.postgresql.util.PSQLException: FATAL: password authentication failed for user "postgres"

The most relevant tip was this:
https://stackoverflow.com/a/25943227/1005607

Open  pg_hba.conf
Change md5 -> TRUST
then restart PgAdmin.

I tried that and restarted PGAdmin but it still asks me for the password when I try to connect:

The task manager in Windows shows some PostgreSQL processes are running. I can't switch them off.

I have tried this and it failed:

pg_ctl restart

ERROR:
pg_ctl: no database directory specified and environment variable PGDATA unset

psql.exe postgres
Password: (none)
ERROR:
psql: fe_sendauth: no password supplied

How can I reset the default password for user 'postgres'?

Body:
Update your pg_hba.conf file to allow for trusted local connections

[root@server] vim pg_hba.conf
>> local all all         trust

then restart your PostgreSQL server

[user@machine] pg_ctl -D C:\PostgreSQL\data restart    (Windows)
[root@server] service postgresql restart            (Linux)

at this point you can connect to your server as postgres user using a local connection without the need to enter a password (omitting the -h parameter when calling the psql command will use a local connection - if you pass -h then this will match the line host all all 0.0.0.0/0 <method> in your pg_hba.conf file)

[root@server] psql -U postgres

You can then alter the postgres user role and set the password to whatever you like using the following command in the psql terminal

[psql] alter role postgres password <new_password>;

Once this is done you can restart your PostgreSQL server again

[user@machine] pg_ctl -D C:\PostgreSQL\data restart     (Windows)
[root@server] service postgresql restart             (Linux)

and at this point your password should be changed to the new password


问:
Is there an expression language to query from flatbuffers (using JAVA)?
I have a generated flatbuffers object in Java. I need to query for a field at runtime based on user input. Is there a way to do that?</p>

答:
There is currently no way to dynamically query fields in Java, you have to know the field's name statically to retrieve its value. So best you can do is if (user_input == "field") return obj.field().

There is a way to find out what fields are in a schema dynamically, by inspecting a binary schema file (which can be generated with flatc --schema myschema.fbs). Sadly, there is no reflection helper code in Java yet that will allow you to use that information to read an actual field (C++ only so far).


问:
regex to find table name from sql query using shell script
I need to find table name from query and store the table name to variable.

Here is the query:

```<code>INSERT INTO CS_POLICY_TERM_PREM_TRANS(SOURCE_SYSTEM_CD)
    VALUES ( ?, ?)
</code>```

答:
INTO\s+\w+

please try this.....

Body:
I need to find table name from query and store the table name to variable.

Here is the query:

INSERT INTO CS_POLICY_TERM_PREM_TRANS(SOURCE_SYSTEM_CD)
    VALUES ( ?, ?)

Body:
INTO\s+\w+

please try this.....


问:
Python random.randrange producing everything but the step
When using this following code:

```<code>import random
sticks = 100
randomstep = random.randint(1, 6)
expertmarbles = random.randrange(1, sticks, 2**randomstep)
</code>```

the output is producing everything excluding the step, so for example i would like this to output a random from these numbers: 2,4,8,16,32,64. However it will output everything but these numbers. Can anyone offer any advice, the reason i'm using variables here is because the amount of sticks will decrease.

答:
Instead of using random.randrange you could use random.choice (docs):

```<code>import random
min_power = 1
max_power = 6
print(random.choice([2**i for i in range(min_power, max_power + 1)]))
</code>```

Body:
When using this following code:

import random
sticks = 100
randomstep = random.randint(1, 6)
expertmarbles = random.randrange(1, sticks, 2**randomstep)

the output is producing everything excluding the step, so for example i would like this to output a random from these numbers: 2,4,8,16,32,64. However it will output everything but these numbers. Can anyone offer any advice, the reason i'm using variables here is because the amount of sticks will decrease.

Body:
Instead of using random.randrange you could use random.choice (docs):

import random
min_power = 1
max_power = 6
print(random.choice([2**i for i in range(min_power, max_power + 1)]))


问:
Does python support character type?
When I am checking with data types I wonder why a char value is returning as string type.

Please see my input and output.

Input:

```<code>a = 'c'

type(a)
</code>```

Output:

```<code>class 'str'
</code>```

答:
There is a bytes type which may be analogous depending on why you are asking.

```<code>>>> b'a'
=> b'a'
</code>```

https://docs.python.org/3/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit

Title: Does python support character type?

Body:
When I am checking with data types I wonder why a char value is returning as string type.

Please see my input and output.

Input:

a = 'c'

type(a)

Output:

class 'str'

Body:
There is a bytes type which may be analogous depending on why you are asking.

>>> b'a'
=> b'a'

https://docs.python.org/3/whatsnew/3.0.html#text-vs-data-instead-of-unicode-vs-8-bit


问:
Chrome Android v62 breaks Cordova plugin loading - deviceready has not fired after 5 seconds
My Cordova app installed on Android OS 6+ (Marshmallow and higher) recently 'broke'when installing Chrome (62.0.3202.84) -- and by this, I mean that random Cordova plugins stop loading properly. Web assets linked are randomly missing, some plugins are 'already defined', and sometimes Cordova itself doesn't load.

It is bizarre -- I've tried just about every version of Cordova-Android and Cordova CLI version possible. It is an Ionic v1 app.

Has anyone experienced strange-ness with Chrome (62.0.3202.84) and their Cordova app? Here is some info:

package.json:

```<code>"cordova-plugin-splashscreen@4.0.1",
    "cordova-plugin-crypt-file@1.1.1",
    "ionic-plugin-keyboard@2.2.1",
    "cordova-plugin-touchid",
    "cordova-plugin-google-analytics@1.7.4",
    "cordova-plugin-network-information@1.3.1",
    "cordova-plugin-market",
    "cordova-plugin-printer@0.7.2",
    "cordova-plugin-keepe-cardio",
    "cordova-plugin-file@4.3.1",
    "cordova-plugin-privacyscreen@0.3.1",
    "cordova-plugin-badge@0.7.2",
    "cordova-plugin-fcm@~2.1.1",
    "cordova-plugin-secure-storage@2.6.3",
    "cordova-custom-config --fetch"
  ],
  "cordovaPlatforms": [
    "ios@4.3",
    "android@6.2.3"
  ],
</code>```

config.xml:

```<code><widget android-versionCode="XXXXXXXXX" id="com.xxxxxx.zzzzz" ios-CFBundleVersion="2.3.0" version="2.3.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">

<preference name="AndroidPersistentFileLocation" value="Compatibility"/>
  <preference name="detect-data-types" value="false"/>
  <preference name="orientation" value="portrait"/>
  <preference name="webviewbounce" value="false"/>
  <preference name="UIWebViewBounce" value="false"/>
  <preference name="DisallowOverscroll" value="true"/>
  <preference name="android-minSdkVersion" value="21"/>
  <preference name="android-targetSdkVersion" value="25" />
  <preference name="BackupWebStorage" value="none"/>
  <preference name="SplashScreenDelay" value="4000"/>
  <preference name="ShowSplashScreenSpinner" value="false"/>
  <preference name="orientation" value="portrait"/>
  <preference name="FadeSplashScreen" value="false"/>
  <preference name="AutoHideSplashScreen" value="true"/>
  <preference name="iosPersistentFileLocation" value="Library"/>
  <preference name="AndroidPersistentFileLocation" value="Compatibility"/>
  <preference name="Fullscreen" value="false"/>
  <preference name="StatusBarOverlaysWebView" value="true"/>
  <preference name="StatusBarBackgroundColor" value="#002740"/>
  <preference name="AndroidPersistentFileLocation" value="Compatibility"/>
  <preference name="SplashScreen" value="screen"/>
  <preference name="StatusBarStyle" value="BlackTranslucent"/>
  <feature name="StatusBar">
    <param name="ios-package" onload="true" value="CDVStatusBar"/>
  </feature>
  <platform name="ios">
    <preference name="deployment-target" value="9.0"/>
    <preference name="KeychainAccessibility" value="WhenUnlockedThisDeviceOnly"/>
    <icon src="resources/ios/icon/icon.png" width="57" height="57"/>
    <icon src="resources/ios/icon/icon@2x.png" width="114" height="114"/>
    <icon src="resources/ios/icon/icon-40.png" width="40" height="40"/>
    <icon src="resources/ios/icon/icon-40@2x.png" width="80" height="80"/>
    <icon src="resources/ios/icon/icon-40@3x.png" width="120" height="120"/>
    <icon src="resources/ios/icon/icon-50.png" width="50" height="50"/>
    <icon src="resources/ios/icon/icon-50@2x.png" width="100" height="100"/>
    <icon src="resources/ios/icon/icon-60.png" width="60" height="60"/>
    <icon src="resources/ios/icon/icon-60@2x.png" width="120" height="120"/>
    <icon src="resources/ios/icon/icon-60@3x.png" width="180" height="180"/>
    <icon src="resources/ios/icon/icon-72.png" width="72" height="72"/>
    <icon src="resources/ios/icon/icon-72@2x.png" width="144" height="144"/>
    <icon src="resources/ios/icon/icon-76.png" width="76" height="76"/>
    <icon src="resources/ios/icon/icon-76@2x.png" width="152" height="152"/>
    <icon src="resources/ios/icon/icon-83.5@2x.png" width="167" height="167"/>
    <icon src="resources/ios/icon/icon-small.png" width="29" height="29"/>
    <icon src="resources/ios/icon/icon-small@2x.png" width="58" height="58"/>
    <icon src="resources/ios/icon/icon-small@3x.png" width="87" height="87"/>
    <splash src="resources/ios/splash/Default-568h@2x~iphone.png" width="640" height="1136"/>
    <splash src="resources/ios/splash/Default-667h.png" width="750" height="1334"/>
    <splash src="resources/ios/splash/Default-736h.png" width="1242" height="2208"/>
    <splash src="resources/ios/splash/Default-Portrait@2x~ipad.png" width="1536" height="2048"/>
    <splash src="resources/ios/splash/Default-Portrait@~ipadpro.png" width="2048" height="2732"/>
    <splash src="resources/ios/splash/Default-Portrait~ipad.png" width="768" height="1024"/>
    <splash src="resources/ios/splash/Default@2x~iphone.png" width="640" height="960"/>
    <splash src="resources/ios/splash/Default~iphone.png" width="320" height="480"/>
  </platform>
  <platform name="android">
    <preference name="android-manifest/application/@android:allowBackup" value="false"/>
    <icon src="resources/android/icon/drawable-ldpi-icon.png" density="ldpi"/>
    <icon src="resources/android/icon/drawable-mdpi-icon.png" density="mdpi"/>
    <icon src="resources/android/icon/drawable-hdpi-icon.png" density="hdpi"/>
    <icon src="resources/android/icon/drawable-xhdpi-icon.png" density="xhdpi"/>
    <icon src="resources/android/icon/drawable-xxhdpi-icon.png" density="xxhdpi"/>
    <icon src="resources/android/icon/drawable-xxxhdpi-icon.png" density="xxxhdpi"/>
    <splash src="resources/android/splash/drawable-port-ldpi-screen.png" density="port-ldpi"/>
    <splash src="resources/android/splash/drawable-port-mdpi-screen.png" density="port-mdpi"/>
    <splash src="resources/android/splash/drawable-port-hdpi-screen.png" density="port-hdpi"/>
    <splash src="resources/android/splash/drawable-port-xhdpi-screen.png" density="port-xhdpi"/>
    <splash src="resources/android/splash/drawable-port-xxhdpi-screen.png" density="port-xxhdpi"/>
    <splash src="resources/android/splash/drawable-port-xxxhdpi-screen.png" density="port-xxxhdpi"/>
  </platform>
  <icon src="resources/android/icon/drawable-xhdpi-icon.png"/>
</widget>
</code>```

project.properties:

```<code>target=android-25
android.library.reference.1=CordovaLib
cordova.system.library.1=com.android.support:appcompat-v7:23.4.0
cordova.system.library.2=com.google.android.gms:play-services-analytics:11.0.1
cordova.system.library.3=com.google.firebase:firebase-core:11.0.1
cordova.system.library.4=com.google.firebase:firebase-messaging:11.0.1
cordova.gradle.include.1=cordova-plugin-badge/XXXXXXXX-badge.gradle
</code>```

ionic-info:

```<code>`Cordova CLI: 6.5.0
Gulp version:  CLI version 3.9.0
Gulp local:
Ionic CLI Version: 1.7.12
Ionic App Lib Version: 0.6.5
ios-deploy version: 1.8.4
ios-sim version: 5.0.4
OS: Mac OS X El Capitan
Node Version: v6.11.5
Xcode version: Xcode 9.1 Build version 9B55`

Sample Stack Trace in Chrome Dev Tools:

`ng-cordova.js Failed to load resource: the server responded with a status of 404 (Not Found)
cordova.js:79 Uncaught module cordova-plugin-file.DirectoryEntry already defined
cordova.js:79 Uncaught module cordova-plugin-file.FileWriter already defined
cordova.js:79 Uncaught module cordova-plugin-file.Metadata already defined
cordova.js:79 Uncaught module cordova-plugin-network-information.network already defined
cordova.js:1469 Uncaught Error: Module cordova-plugin-file.DirectoryReader does not exist.
    at addEntry (cordova.js:1469)
    at Object.exports.clobbers (cordova.js:1479)
    at onScriptLoadingComplete (cordova.js:1893)
    at scriptLoadedCallback (cordova.js:1926)
    at HTMLScriptElement.<anonymous> (cordova.js:1880)
app.js:7574 Creating database
app.js:7592 createSecureStorage called
app.js:5574 reset access and refreshtoken
vendor.js:121760 WebSocket connection to 'ws://localhost:9485/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
connect @ vendor.js:121760
favicon.ico Failed to load resource: the server responded with a status of 404 (Not Found)
3vendor.js:121760 WebSocket connection to 'ws://localhost:9485/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
connect @ vendor.js:121760
cordova.js:1223 deviceready has not fired after 5 seconds.
cordova.js:1216 Channel not fired: onPluginsReady
cordova.js:1216 Channel not fired: onCordovaReady
24vendor.js:121760 WebSocket connection to 'ws://localhost:9485/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
connect @ vendor.js:121760
</code>```

I have tried cordova-android versions:

5.0.0 - 6.4.0 (And some nightly 6.5.xx versions).

The key error is, again, the failure of Cordova's Device Ready to fire:

```<code>cordova.js:1223 deviceready has not fired after 5 seconds.
cordova.js:1216 Channel not fired: onPluginsReady
cordova.js:1216 Channel not fired: onCordovaReady
</code>```

This is a lot of info, but I can try to provide more if needed. All of this compiles well on any version of Chrome-Android below 62. Any help would be superbly valued.

答:
So I found out sort of a fix..

I ended up adding Crosswalk. Yeah, yeah, that was the very first thing I tried. I managed to get a successful build with Cordova-Android 6.2.3, Node 6.10.3, Ionic CLI 2.1.7, Cordova 6.5.0.. but the build always crashed upon start.

I ended up with these commands, and it worked:

```<code>ionic state reset && sh bin/copyGradle && ionic build android --verbose
cordova plugin add cordova-plugin-crosswalk-webview
ionic build android --verbose
</code>```

I can reproduce this successful build.
If I have time, perhaps I could fork Crosswalk and see if I could keep it maintained. Maybe I'll switch to Yarn so I can have a cached copy of the Crosswalk versions I need.. since I've noticed that those servers have been on/offline sporadically as of late.

If you're fighting the Ionic 1 battle still, hang in there.

Body:
My Cordova app installed on Android OS 6+ (Marshmallow and higher) recently 'broke'when installing Chrome (62.0.3202.84) -- and by this, I mean that random Cordova plugins stop loading properly. Web assets linked are randomly missing, some plugins are 'already defined', and sometimes Cordova itself doesn't load.

It is bizarre -- I've tried just about every version of Cordova-Android and Cordova CLI version possible. It is an Ionic v1 app.

Has anyone experienced strange-ness with Chrome (62.0.3202.84) and their Cordova app? Here is some info:

package.json:

"cordova-plugin-splashscreen@4.0.1",
    "cordova-plugin-crypt-file@1.1.1",
    "ionic-plugin-keyboard@2.2.1",
    "cordova-plugin-touchid",
    "cordova-plugin-google-analytics@1.7.4",
    "cordova-plugin-network-information@1.3.1",
    "cordova-plugin-market",
    "cordova-plugin-printer@0.7.2",
    "cordova-plugin-keepe-cardio",
    "cordova-plugin-file@4.3.1",
    "cordova-plugin-privacyscreen@0.3.1",
    "cordova-plugin-badge@0.7.2",
    "cordova-plugin-fcm@~2.1.1",
    "cordova-plugin-secure-storage@2.6.3",
    "cordova-custom-config --fetch"
  ],
  "cordovaPlatforms": [
    "ios@4.3",
    "android@6.2.3"
  ],

config.xml:

<widget android-versionCode="XXXXXXXXX" id="com.xxxxxx.zzzzz" ios-CFBundleVersion="2.3.0" version="2.3.0" xmlns="http://www.w3.org/ns/widgets" xmlns:cdv="http://cordova.apache.org/ns/1.0">

<preference name="AndroidPersistentFileLocation" value="Compatibility"/>
  <preference name="detect-data-types" value="false"/>
  <preference name="orientation" value="portrait"/>
  <preference name="webviewbounce" value="false"/>
  <preference name="UIWebViewBounce" value="false"/>
  <preference name="DisallowOverscroll" value="true"/>
  <preference name="android-minSdkVersion" value="21"/>
  <preference name="android-targetSdkVersion" value="25" />
  <preference name="BackupWebStorage" value="none"/>
  <preference name="SplashScreenDelay" value="4000"/>
  <preference name="ShowSplashScreenSpinner" value="false"/>
  <preference name="orientation" value="portrait"/>
  <preference name="FadeSplashScreen" value="false"/>
  <preference name="AutoHideSplashScreen" value="true"/>
  <preference name="iosPersistentFileLocation" value="Library"/>
  <preference name="AndroidPersistentFileLocation" value="Compatibility"/>
  <preference name="Fullscreen" value="false"/>
  <preference name="StatusBarOverlaysWebView" value="true"/>
  <preference name="StatusBarBackgroundColor" value="#002740"/>
  <preference name="AndroidPersistentFileLocation" value="Compatibility"/>
  <preference name="SplashScreen" value="screen"/>
  <preference name="StatusBarStyle" value="BlackTranslucent"/>
  <feature name="StatusBar">
    <param name="ios-package" onload="true" value="CDVStatusBar"/>
  </feature>
  <platform name="ios">
    <preference name="deployment-target" value="9.0"/>
    <preference name="KeychainAccessibility" value="WhenUnlockedThisDeviceOnly"/>
    <icon src="resources/ios/icon/icon.png" width="57" height="57"/>
    <icon src="resources/ios/icon/icon@2x.png" width="114" height="114"/>
    <icon src="resources/ios/icon/icon-40.png" width="40" height="40"/>
    <icon src="resources/ios/icon/icon-40@2x.png" width="80" height="80"/>
    <icon src="resources/ios/icon/icon-40@3x.png" width="120" height="120"/>
    <icon src="resources/ios/icon/icon-50.png" width="50" height="50"/>
    <icon src="resources/ios/icon/icon-50@2x.png" width="100" height="100"/>
    <icon src="resources/ios/icon/icon-60.png" width="60" height="60"/>
    <icon src="resources/ios/icon/icon-60@2x.png" width="120" height="120"/>
    <icon src="resources/ios/icon/icon-60@3x.png" width="180" height="180"/>
    <icon src="resources/ios/icon/icon-72.png" width="72" height="72"/>
    <icon src="resources/ios/icon/icon-72@2x.png" width="144" height="144"/>
    <icon src="resources/ios/icon/icon-76.png" width="76" height="76"/>
    <icon src="resources/ios/icon/icon-76@2x.png" width="152" height="152"/>
    <icon src="resources/ios/icon/icon-83.5@2x.png" width="167" height="167"/>
    <icon src="resources/ios/icon/icon-small.png" width="29" height="29"/>
    <icon src="resources/ios/icon/icon-small@2x.png" width="58" height="58"/>
    <icon src="resources/ios/icon/icon-small@3x.png" width="87" height="87"/>
    <splash src="resources/ios/splash/Default-568h@2x~iphone.png" width="640" height="1136"/>
    <splash src="resources/ios/splash/Default-667h.png" width="750" height="1334"/>
    <splash src="resources/ios/splash/Default-736h.png" width="1242" height="2208"/>
    <splash src="resources/ios/splash/Default-Portrait@2x~ipad.png" width="1536" height="2048"/>
    <splash src="resources/ios/splash/Default-Portrait@~ipadpro.png" width="2048" height="2732"/>
    <splash src="resources/ios/splash/Default-Portrait~ipad.png" width="768" height="1024"/>
    <splash src="resources/ios/splash/Default@2x~iphone.png" width="640" height="960"/>
    <splash src="resources/ios/splash/Default~iphone.png" width="320" height="480"/>
  </platform>
  <platform name="android">
    <preference name="android-manifest/application/@android:allowBackup" value="false"/>
    <icon src="resources/android/icon/drawable-ldpi-icon.png" density="ldpi"/>
    <icon src="resources/android/icon/drawable-mdpi-icon.png" density="mdpi"/>
    <icon src="resources/android/icon/drawable-hdpi-icon.png" density="hdpi"/>
    <icon src="resources/android/icon/drawable-xhdpi-icon.png" density="xhdpi"/>
    <icon src="resources/android/icon/drawable-xxhdpi-icon.png" density="xxhdpi"/>
    <icon src="resources/android/icon/drawable-xxxhdpi-icon.png" density="xxxhdpi"/>
    <splash src="resources/android/splash/drawable-port-ldpi-screen.png" density="port-ldpi"/>
    <splash src="resources/android/splash/drawable-port-mdpi-screen.png" density="port-mdpi"/>
    <splash src="resources/android/splash/drawable-port-hdpi-screen.png" density="port-hdpi"/>
    <splash src="resources/android/splash/drawable-port-xhdpi-screen.png" density="port-xhdpi"/>
    <splash src="resources/android/splash/drawable-port-xxhdpi-screen.png" density="port-xxhdpi"/>
    <splash src="resources/android/splash/drawable-port-xxxhdpi-screen.png" density="port-xxxhdpi"/>
  </platform>
  <icon src="resources/android/icon/drawable-xhdpi-icon.png"/>
</widget>

project.properties:

target=android-25
android.library.reference.1=CordovaLib
cordova.system.library.1=com.android.support:appcompat-v7:23.4.0
cordova.system.library.2=com.google.android.gms:play-services-analytics:11.0.1
cordova.system.library.3=com.google.firebase:firebase-core:11.0.1
cordova.system.library.4=com.google.firebase:firebase-messaging:11.0.1
cordova.gradle.include.1=cordova-plugin-badge/XXXXXXXX-badge.gradle

ionic-info:

`Cordova CLI: 6.5.0
Gulp version:  CLI version 3.9.0
Gulp local:
Ionic CLI Version: 1.7.12
Ionic App Lib Version: 0.6.5
ios-deploy version: 1.8.4
ios-sim version: 5.0.4
OS: Mac OS X El Capitan
Node Version: v6.11.5
Xcode version: Xcode 9.1 Build version 9B55`

Sample Stack Trace in Chrome Dev Tools:

`ng-cordova.js Failed to load resource: the server responded with a status of 404 (Not Found)
cordova.js:79 Uncaught module cordova-plugin-file.DirectoryEntry already defined
cordova.js:79 Uncaught module cordova-plugin-file.FileWriter already defined
cordova.js:79 Uncaught module cordova-plugin-file.Metadata already defined
cordova.js:79 Uncaught module cordova-plugin-network-information.network already defined
cordova.js:1469 Uncaught Error: Module cordova-plugin-file.DirectoryReader does not exist.
    at addEntry (cordova.js:1469)
    at Object.exports.clobbers (cordova.js:1479)
    at onScriptLoadingComplete (cordova.js:1893)
    at scriptLoadedCallback (cordova.js:1926)
    at HTMLScriptElement.<anonymous> (cordova.js:1880)
app.js:7574 Creating database
app.js:7592 createSecureStorage called
app.js:5574 reset access and refreshtoken
vendor.js:121760 WebSocket connection to 'ws://localhost:9485/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
connect @ vendor.js:121760
favicon.ico Failed to load resource: the server responded with a status of 404 (Not Found)
3vendor.js:121760 WebSocket connection to 'ws://localhost:9485/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
connect @ vendor.js:121760
cordova.js:1223 deviceready has not fired after 5 seconds.
cordova.js:1216 Channel not fired: onPluginsReady
cordova.js:1216 Channel not fired: onCordovaReady
24vendor.js:121760 WebSocket connection to 'ws://localhost:9485/' failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED
connect @ vendor.js:121760

I have tried cordova-android versions:

5.0.0 - 6.4.0 (And some nightly 6.5.xx versions).

The key error is, again, the failure of Cordova's Device Ready to fire:

cordova.js:1223 deviceready has not fired after 5 seconds.
cordova.js:1216 Channel not fired: onPluginsReady
cordova.js:1216 Channel not fired: onCordovaReady

This is a lot of info, but I can try to provide more if needed. All of this compiles well on any version of Chrome-Android below 62. Any help would be superbly valued.

Body:
So I found out sort of a fix..

I ended up adding Crosswalk. Yeah, yeah, that was the very first thing I tried. I managed to get a successful build with Cordova-Android 6.2.3, Node 6.10.3, Ionic CLI 2.1.7, Cordova 6.5.0.. but the build always crashed upon start.

I ended up with these commands, and it worked:

ionic state reset && sh bin/copyGradle && ionic build android --verbose
cordova plugin add cordova-plugin-crosswalk-webview
ionic build android --verbose

I can reproduce this successful build.
If I have time, perhaps I could fork Crosswalk and see if I could keep it maintained. Maybe I'll switch to Yarn so I can have a cached copy of the Crosswalk versions I need.. since I've noticed that those servers have been on/offline sporadically as of late.

If you're fighting the Ionic 1 battle still, hang in there.


问:
WiX tricks and tips
We've been using WiX for a while now, and despite the usual gripes about ease of use, it's going reasonably well. What I'm looking for is useful advice regarding:

Setting up a WiX project (layout, references, file patterns)

Integrating WiX into solutions, and build/release processes

Configuring installers for new installations and upgrades

Any good WiX hacks you'd like to share

答:
We display the product version somewhere (tiny) in the first screen of the GUI. Because people tend to make mistakes in picking the right version every time. (And keep us developers searching for ages..)

We've set up TFSBuild to also generate transforms (.mst files) with the configuration for our different environments. (We know about all environments we need to deploy to).

Since the original weblog post by Grant Holliday is down, I copy pasted its contents here:

MSBuild task to generate MSI Transform files from XMLMarch 11 2008

In my previous post I described how you can use MSI Transform (*.mst) files to separate environment-specific configuration settings from a generic MSI package.

Although this provides a level of flexibility in your configuration, there are two down-sides of Transform files:

They’re a binary format

You can’t “edit” or “view” a transform file. You have to apply it or re-create it to see what changes it includes.

Fortunately we can use the Microsoft Windows Installer Object Library (c:windowssystem32msi.dll) to open MSI “databases” and create transform files.

Credits go again to Alex Shevchuk – From MSI to WiX – Part 7 – Customising installation using Transforms for showing us how to achieve this with VbScript. Essentially all I’ve done is taken Alex’s example and using Interop.WindowsInstaller.dll I’ve implemented an MSBuild task.
The  MSBuild Task

Download the source code & example transforms.xml here (~7Kb Zipped VS2008 Solution)

OwnerDisplayName: Si

Title: WiX tricks and tips

LastEditorDisplayName: Si

OwnerDisplayName: thijs


问:
How to select all elements whose id contains a particular substring?
I want to select all elements whose id contains a particular substring. For example for these:

```<code><div id="foobootoo"><div>
<div id="foowoohoo"><div>
<div id="foodoowoo"><div>
<div id="soobootoo"><div>
</code>```

I want to get elements that has foo in the id.

答:
First of all your markup seems broken. Once you fix it like this:

```<code><div id="foobootoo"></div>
<div id="foowoohoo"></div>
<div id="foodoowoo"></div>
<div id="soobootoo"></div>
</code>```

if you use this xpath you will get only the first three nodes: //div[contains(@id, 'foo')].

Body:
I want to select all elements whose id contains a particular substring. For example for these:

I want to get elements that has foo in the id.

Body:
First of all your markup seems broken. Once you fix it like this:

<div id="foobootoo"></div>
<div id="foowoohoo"></div>
<div id="foodoowoo"></div>
<div id="soobootoo"></div>

if you use this xpath you will get only the first three nodes: //div[contains(@id, 'foo')].


问:
Custom navigation bar using Xamarin forms with prism broken
I'm using Prism Library for Xamarin.Forms.

And I'm going to create custom navigation bar via Control template. (Reason of creating custom navigation bar - I didn't find solution to make navigation bar transparent for display background image, also I will probably customize my navigation bar and add some controls on it).

<ControlTemplate x:Key="NavigationPageTemplate">
    <AbsoluteLayout BackgroundColor="Transparent">

        <Image AbsoluteLayout.LayoutBounds="0,0,1,1"
               AbsoluteLayout.LayoutFlags="All"
               Aspect="AspectFill"
               Source="{TemplateBinding BackgroundImageEx}" />

        <ContentView Padding="0,50,0,0"
                     AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All">
            <ContentPresenter />
        </ContentView>

        <ContentView AbsoluteLayout.LayoutBounds="0,0,1,AutoSize"
                     AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
                     BackgroundColor="Transparent">
            <ContentView.Padding>
                <OnPlatform x:TypeArguments="Thickness"
                            Android="10"
                            iOS="10, 20, 10, 0" />
            </ContentView.Padding>

            <controls:ImageButton Command="{TemplateBinding GoBackCommand}"
                                  HeightRequest="30"
                                  HorizontalOptions="StartAndExpand"
                                  Source="ic_back.png"
                                  WidthRequest="30">

            </controls:ImageButton>

        </ContentView>
    </AbsoluteLayout>
</ControlTemplate>
```

<p>And my problem is to process back button press with Prism Navigation.
I've tried to process click on MyApp.xaml.cs file.</p>

<pre class="lang-xml prettyprint-override"><code>private void Button_OnClicked(object sender, EventArgs e)
{
    NavigationService.GoBackAsync();
}
</code>```

And it seems to have different navigation stack because it shows after press my first page.

I had Navigation this way:

Navigate("FirstPage"); -> Navigate(MasterDetail/NavigationPage/ViewA) -> Navigate("ViewB")
ViewB - uses Control template.

When I click custom back button on ViewB NavigationService back me to FirstPage. It is incorrect for me. I should back to ViewA!

Another question Should first page be saved when we change App.MainPage?

答: See the discussion of described problem on https://github.com/PrismLibrary/Prism/issues/1262</p>

Body:
I'm using Prism Library for Xamarin.Forms.

And I'm going to create custom navigation bar via Control template. (Reason of creating custom navigation bar - I didn't find solution to make navigation bar transparent for display background image, also I will probably customize my navigation bar and add some controls on it).

<ControlTemplate x:Key="NavigationPageTemplate">
    <AbsoluteLayout BackgroundColor="Transparent">

        <Image AbsoluteLayout.LayoutBounds="0,0,1,1"
               AbsoluteLayout.LayoutFlags="All"
               Aspect="AspectFill"
               Source="{TemplateBinding BackgroundImageEx}" />

        <ContentView Padding="0,50,0,0"
                     AbsoluteLayout.LayoutBounds="0,0,1,1"
                     AbsoluteLayout.LayoutFlags="All">
            <ContentPresenter />
        </ContentView>

        <ContentView AbsoluteLayout.LayoutBounds="0,0,1,AutoSize"
                     AbsoluteLayout.LayoutFlags="PositionProportional, WidthProportional"
                     BackgroundColor="Transparent">
            <ContentView.Padding>
                <OnPlatform x:TypeArguments="Thickness"
                            Android="10"
                            iOS="10, 20, 10, 0" />
            </ContentView.Padding>

            <controls:ImageButton Command="{TemplateBinding GoBackCommand}"
                                  HeightRequest="30"
                                  HorizontalOptions="StartAndExpand"
                                  Source="ic_back.png"
                                  WidthRequest="30">

            </controls:ImageButton>

        </ContentView>
    </AbsoluteLayout>
</ControlTemplate>

And my problem is to process back button press with Prism Navigation.
I've tried to process click on MyApp.xaml.cs file.

private void Button_OnClicked(object sender, EventArgs e)
{
    NavigationService.GoBackAsync();
}

And it seems to have different navigation stack because it shows after press my first page.

I had Navigation this way:

Navigate("FirstPage"); -> Navigate(MasterDetail/NavigationPage/ViewA) -> Navigate("ViewB")
ViewB - uses Control template.

When I click custom back button on ViewB NavigationService back me to FirstPage. It is incorrect for me. I should back to ViewA!

Another question Should first page be saved when we change App.MainPage?